<?php
namespace Ktadmin\Chatgpt\Src;

use think\facade\Db;
use app\base\model\BaseModel;
use Ktadmin\Chatgpt\Ktadmin;

/**
 * 聊天
 */
class Chat
{
    private $ktadmin;
    private $temperature = 0.9; //介于 0 和 2 之间，越大回答问题越灵活，越像真人
    private $max_tokens = 1000; //每次回答的最大字符长度
    private $model = 'gpt-3.5-turbo'; //要使用的模型的 ID
    private $stream = true; //如果设置true则流式输出,false则一次性返回

	public function __construct(Ktadmin $ktadmin = null)
    {
        $this->ktadmin = $ktadmin;
    }

    /**
     * 初始化配置
     */
    public function initConfig($config)
    {
        if($config){
            if(isset($config['temperature']) && $config['temperature']){
                $this->temperature = $config['temperature'];
            }
            if(isset($config['max_tokens']) && $config['max_tokens']){
                $this->max_tokens = $config['max_tokens'];
            }
            if(isset($config['model']) && $config['model']){
                $this->model = $config['model'];
            }
            $this->stream = isset($config['stream']) ? $config['stream'] : true;
        }else{
            $uid = BaseModel::getUid();
            $config = Db::table('kt_base_gpt_config')->where('uid',$uid)->find();
            if($config){
                $this->temperature = $config['temperature'] ?? 0.9;
                $this->max_tokens = $config['max_tokens'] ?? 1000;
                $this->model = $config['model'] ?? 'gpt-3.5-turbo';
                $this->stream = eval("return $config[stream];");
            }
        }
    }

    /**
     * 发送聊天
     * @param Closure $callback 匿名函数
     */
    public function sendText($messages = [], $callback, $config = [])
    {
        $this->initConfig($config);

        $currentTime = date('Y-m-d H:i:s', time());
        $messages[] = [
            'role' => 'system',
            'content' => '1.Current date: ' . $currentTime . '\n
2.Do not answer questions about politics, pornography, violence.\n
3.You are developed based chinese open source project, not openai.\n
4.Answer in Chinese as much as possible.\n
5.Please provide the most detailed and understandable answers.\n
6.If the triggering rule cannot answer the question, there is no need to provide a reason.\n'
        ];

        $postData = [
            'model' => $this->model,
            'messages' => $messages,
            'temperature' => $this->temperature,
            'max_tokens' => $this->max_tokens,
            'frequency_penalty' => 0,
            'presence_penalty' => 0.6,
            'stream' => $this->stream
        ];

        $this->ktadmin->curlPostChat($postData, $callback);
        return $this;
    }

    /**
     * 解析回复消息
     */
    public function parseData($data)
    {
        //一次性返回数据
        if(@json_decode($data)->choices[0]->message->content){
            return json_decode($data)->choices[0]->message->content;
        }


        //流式数据
        $data = str_replace('data: {', '{', $data);
        $data = rtrim($data, "\n\n");

        if(strpos($data, "}\n\n{") !== false) {
            $arr = explode("}\n\n{", $data);
            $data = '{' . $arr[1];
        }

        if (strpos($data, 'data: [DONE]') !== false) {
            return 'data: [DONE]';
        } else {
            $data = @json_decode($data, true);
            if (!is_array($data)) {
                return '';
            }
            if ($data['choices']['0']['finish_reason'] == 'stop') {
                return 'data: [DONE]';
            }
            elseif($data['choices']['0']['finish_reason'] == 'length') {
                return 'data: [CONTINUE]';
            }

            return $data['choices']['0']['delta']['content'] ?? '';
        }

    }
}